<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>图像预加载与懒加载</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        #image {
            background-color: red;
        }
    </style>
</head>
<body>
    <div id="image"></div>

<script>
    // 预加载(基础)
    function loadImg(url, callback) {
        let img = new Image();
        img.src = url;
        if (img.complete) {
            // 如果图片已经缓存
            console.log("缓存调用");
            callback.call(img);
            return
        }
        img.onload = function () {
            // 图片下载完成，异步调用callback
            callback.call(img)
        }
    }

    var imgReady = (function(){
        var list = [], // 存储加载图片任务的列表
            intervalId = null;  // 计时器id

        // 用来执行加载任务的队列
        var queue = function(){

            for(var i = 0; i < list.length; i++){
                list[i].end ? list.splice(i--,1) : list[i](); // 如果当前任务执行完毕，则踢出队列，否则就执行任务
            }
            !list.length && stop();  // 任务队列全部执行完毕， 停止所有定时器
        };

        // 停止所有定时器队列
        var stop = function(){
            clearInterval(intervalId);
            intervalId = null;
        }
        return function(url, ready, error) {
            var onready = {},
                width,
                height,
                newWidth,
                newHeight,
                img = new Image();
            img.src = url;

            // 如果图片被缓存，则直接返回缓存数据
            if(img.complete) {
                ready.call(img);
                return;
            }
            width = img.width;
            height = img.height;

            // 加载错误后的事件
            img.onerror = function () {
                error && error.call(img);
                onready.end = true;
                img = img.onload = img.onerror = null;
            };

            // 图片尺寸就绪
            var onready = function() {
                newWidth = img.width;
                newHeight = img.height;
                if (newWidth !== width || newHeight !== height ||
                    // 如果图片已经在其他地方加载可使用面积检测
                    newWidth * newHeight > 1024
                ) {
                    ready.call(img);
                    onready.end = true; // onready函数对象绑定一个end属性，表示加载结束
                };
            };
            onready();
            // 完全加载完毕的事件
            img.onload = function () {
                // onload在定时器时间差范围内可能比onready快
                // 这里进行检查并保证onready优先执行
                !onready.end && onready(); // 如果没有加载完毕，就赶紧继续加载
                // IE gif动画会循环执行onload，置空onload即可
                img = img.onload = img.onerror = null;
            };


            // 加入队列中定期执行
            if (!onready.end) {
                list.push(onready);
                // 无论何时只允许出现一个定时器，减少浏览器性能损耗
                if (intervalId === null) {
                    intervalId = setInterval(queue, 40); // 每40ms加载一个图片
                };
            };
        }
    })();
    window.onload = function () {
        setTimeout(function(){
            imgReady('https://www.z4a.net/images/2019/08/12/localhost_8080_iPhone-6_7_8-Plus-1.md.png',function(){
                var divElem = document.querySelector('#image');
                divElem.style.width = this.width + 'px';
                divElem.style.height = this.height + 'px';
                setTimeout(()=>{
                    divElem.append(this)
                }, 500);
            },()=>{
                console.log('error');
            })
        },1000);
    }
</script>
</body>
</html>
